package org.korifey.ffbdd.impl.op;

import java.nio.ByteBuffer;

import org.korifey.ffbdd.api.IBddBackend;
import org.korifey.ffbdd.api.INode;
import org.korifey.ffbdd.api.op.IOpCache;
import org.korifey.ffbdd.api.op.IOpCachePair;
import org.korifey.ffbdd.api.op.IOperation;
import org.korifey.ffbdd.api.op.OpCacheKey;


public class OpCacheBitvector implements IOpCache {
	
	public static final int BYTES_PER_NODE = 12;
	
	byte[] tetranodes; // Array of 12-byte octet. Each octet contains 3 nodes and operation, each node - 3,5 byte; OP code is 1,5 byte. 
					   // In case of 'c = apply(a,b, op)': a, b - first 6 bytes, c - 3 bytes next, OP code - 1 byte, then half-byte tails of a,b,c and then half-byte OP code tail.  
	int size;
	IBddBackend backend; 
	
	public OpCacheBitvector(IBddBackend backend) {
		this.backend = backend;
	}
	
	public void init(int cacheSize) {
		size = cacheSize;
		tetranodes = new byte[cacheSize * BYTES_PER_NODE];
	}
	
	
	public void put(OpCacheKey key, INode value) {		
		OpCachePairBitvector.convertToBytes(key, value, tetranodes, index(key)*BYTES_PER_NODE);				
	}
	
	private IOpCachePair getPair(int index) {
		return OpCachePairBitvector.parse(tetranodes, index*BYTES_PER_NODE, backend);
	}
	
	public boolean contains(OpCacheKey key) {		
		IOpCachePair p = getPair(index(key));
		return  (p.getValue() != null);
	}
	
	public INode get(OpCacheKey key) {
		IOpCachePair p = getPair(index(key));
		return p.getValue();
	}
	
	private int index(OpCacheKey key) {
		int res = key.hashCode() % size;
		if (res <0) res += size;
		return res;
	}
	
	
	
	
	public static void registerOperation(IOperation op) {
		OpCachePairBitvector.registerOperation(op);
	}
}
